var data = {
  isDiscoverying: false,
  isConnected: false,
  ble_device: null,
  foundDevices: [],
  isConnecting: false,
  service_uuid: "",
  char_uuid: "",
}

var private_data = {
  showDialogEnable: true,
  showDebugMsgEnable: true,
}

function setShowDialogEnable(enable) {
  private_data.showDialogEnable = enable
}

function getShowDialogEnable() {
  return private_data.showDialogEnable
}

function setshowDebugMsgEnable(enable) {
  private_data.showDebugMsgEnable = enable
}

function getshowDebugMsgEnable() {
  return private_data.showDebugMsgEnable
} 

function ble_startDiscovery() {
  // var that = this
  wx.startBluetoothDevicesDiscovery({
    allowDuplicatesKey: false,

    success: function(res) {
      data.isDiscoverying = true
      data.foundDevices = []
      data.ble_device = null
      data.isConnected = false

      if (private_data.showDialogEnable) {
        wx.showLoading({
          title: 'Searching Bluetooth devices...',
        })
      }
    },
  })
}

function ble_failCallback(res) {

}

function ble_openAdaptorandStartDiscovery() {
  // var that = this
  wx.openBluetoothAdapter({
    success: function(res) {
      ble_startDiscovery()
      return true
    },
    fail: function(res) {
      if (private_data.showDialogEnable) {
        wx.showModal({
          title: 'Warning',
          content: 'Please check bluetooth wether turn on and try again.',
          showCancel: false,
          success: function (res) {

          }
        })
        ble_failCallback(res)
      }
      return false
    }
  })
}

function ble_onAdapterStatesChanged() {
  wx.onBluetoothAdapterStateChange(function(res){
    if(!res.available) {
      if(private_data.showDebugMsgEnable) {
        console.log("BLE res not available")
      }
      ble_failCallback(res)
      
    }
  })
}

function ble_onDeviceFound(ble_FoundEndCheckCallback) {
  // var that = this
  wx.onBluetoothDeviceFound(function(res){
    let isNewDevice = true
    // If this is a single device result
    if (res.deviceId) {
      // Ergodic
      data.foundDevices.forEach(function (foundDev, index) {
        if (res.deviceId == foundDev.deviceId) {
          isNewDevice = false
        }
      })
      // If this is a new device
      if(isNewDevice) {
        data.foundDevices.push(res)
      }
    } else if(res.devices) {
      // Else if devices list
      data.foundDevices.forEach(function (foundDev, index) {
        if (res.devices[0].deviceId == foundDev.deviceId) {
          isNewDevice = false
        }
      })
      // If this is a new device
      if (isNewDevice) {
        data.foundDevices.push(res.devices[0])
      }
    } else if (res[0]) {
      // Ergodic
      data.foundDevices.forEach(function (foundDev, index) {
        if (res[0].deviceId == foundDev.deviceId) {
          newDevice = false
        }
      })
      // If this is a new device
      if (isNewDevice) {
        data.foundDevices.push(res[0])
      }
    }
    
    if (isNewDevice == true) {
      // if (private_data.showDebugMsgEnable) {
      //   console.log(data.foundDevices)
      // }
      if (ble_FoundEndCheckCallback) {
        ble_FoundEndCheckCallback()
      }
      
    }

  })
}

function ble_getDeviceinFoundDeviceListByName(ble_name) {
  var found_dev = null
  data.foundDevices.forEach(function (dev, index) {
    if(dev.name == ble_name) {
      // if(private_data.showDebugMsgEnable) {
      //   console.log("Device found: ble_name")
      // }
      found_dev = dev
      data.ble_device = dev
    }
  })
  return found_dev
}

function ble_onConnectStateChange() {
  wx.onBLEConnectionStateChange(function(res){
    data.isConnected = res.connected
  })
}

function ble_connectToDevice(ble_connectCallback) {

  if(!data.isConnected) {
    if(data.ble_device == null) {
      if(private_data.showDebugMsgEnable) {
        console.log("ble device null error")
      }
      if(private_data.showDialogEnable) {
        wx.showToast({
          title: 'Bluetooth device error',
          icon: 'failed',
          showCancel: false
        })
      }
    } else {
      // data.isConnected = true
      if (!data.isConnecting) {
        data.isConnecting = true
        if (private_data.showDialogEnable) {
          wx.showLoading({
            title: 'Connecting...',
          })
        }
        wx.createBLEConnection({
          deviceId: data.ble_device.deviceId,
          success: function (res) {
            if (private_data.showDebugMsgEnable) {
              console.log("Connect success!")
            }

            if (private_data.showDialogEnable) {
              wx.showToast({
                title: 'Connected!',
                icon: 'success',
                duration: 1000,
                showCancel: false
              })

            }
            data.isConnected = true
            data.isConnecting = false
            if (ble_connectCallback) {
              ble_connectCallback()
            }

          },
          fail: function (res) {
            if (private_data.showDebugMsgEnable) {
              console.log("Connect failed")
            }
            if (private_data.showDialogEnable) {
              wx.showToast({
                title: 'Connect failed',
                icon: 'failed',
                duration: 1000,
                showCancel: false
              })
            }
            data.isConnected = false
            data.isConnecting = false
            if (ble_connectCallback) {
              ble_connectCallback()
            }
          }
        })
      }
    }
    
  } else {
    if(private_data.showDebugMsgEnable) {
      console.log("Already connect")
    }
    if(private_data.showDialogEnable) {
      wx.showToast({
        title: 'Already connect',
        icon: 'failed',
        duration: 1000,
        showCancel: false
      })
    }
    if (ble_connectCallback) {
      ble_connectCallback()
    }
  }
}

function ble_stopDiscovery(ble_stopedDiscoveryCallback) {
  if(data.isDiscoverying) {
    data.isDiscoverying = false
    wx.stopBluetoothDevicesDiscovery({
      success: function(res) {
        

        if(private_data.showDebugMsgEnable) {
          console.log("Stop discovery success")
        }
        
        // Hide discovery dialog before
        if(private_data.showDialogEnable) {
          wx.hideLoading()
        }
        if (ble_stopedDiscoveryCallback) {
          ble_stopedDiscoveryCallback()
        }
        

        return true
      },
      fail: function(res) {
        data.isDiscoverying = true
        if(private_data.showDebugMsgEnable) {
          console.log("Stop discovery failed")
        }
        if (ble_stopedDiscoveryCallback) {
          ble_stopedDiscoveryCallback()
        }
      }
    })
  } else {
    // console.log("not discovery")
    if (ble_stopedDiscoveryCallback) {
      ble_stopedDiscoveryCallback()
    }
  }
  return false
}

function ble_disconnect(ble_disconnectCallback) {
  if(data.isConnected) {
    data.isConnected = false
    wx.closeBLEConnection({
      deviceId: data.ble_device.deviceId,
      success: function(res) {
        if(private_data.showDialogEnable) {
          wx.showToast({
            title: 'Disconnect',
            icon: 'success',
            duration: 1000,
            showCancel: false
          })
        }
        if (ble_disconnectCallback) {
          ble_disconnectCallback()
        }
        
      },
      fail: function(res) {
        ble_getDevice = true
        if (private_data.showDialogEnable) {
          wx.showToast({
            title: 'Disconnect failed',
            icon: 'failed',
            duration: 1000,
            showCancel: false
          })
        }
        if (ble_disconnectCallback) {
          ble_disconnectCallback()
        }
      },
      
    })
  } else {
    if(private_data.showDebugMsgEnable) {
      console.log("ble not disconnect")
    }
    if (private_data.showDialogEnable) {
      wx.showToast({
        title: 'Not connected',
        icon: 'failed',
        duration: 1000,
        showCancel: false
      })
    }
    if (ble_disconnectCallback) {
      ble_disconnectCallback()
    }

  }
}

function ble_setDevice(dev) {
  data.ble_device = dev
}

function ble_getDevice() {
  return data.ble_device
}

function ble_turnOnNotify(service_uuid, char_uuid, ble_turnOnNotifyCallback) {
  if(data.isConnected) {
    wx.getBLEDeviceServices({
      deviceId: data.ble_device.deviceId,
      success: function(res) {
        res.services.forEach(function(service, index) {
          if(service.uuid == service_uuid) {
            // Find the service
            wx.getBLEDeviceCharacteristics({
              deviceId: data.ble_device.deviceId,
              serviceId: service.uuid,
              success: function(res) {
                res.characteristics.forEach(function(char, index) {
                  if(char.uuid == char_uuid) {
                    data.service_uuid = service.uuid
                    data.char_uuid = char.uuid
                    console.log(data.service_uuid + " " + data.char_uuid)
                    // Find the char
                    wx.notifyBLECharacteristicValueChange({
                      deviceId: data.ble_device.deviceId,
                      serviceId: service.uuid,
                      characteristicId: char.uuid,
                      state: true,
                      success: function(res) {
                        if(private_data.showDebugMsgEnable) {
                          console.log("Turn on notify success")
                        }
                        if (ble_turnOnNotifyCallback) {
                          ble_turnOnNotifyCallback()
                        }
                      },
                    })
                  }
                })
              },
            })
          }
        })
      },
    })
  } else {
    if(private_data.showDebugMsgEnable) {
      console.log("BLE not connect")
    }
  }
}



function ble_getNotifyData(ble_getNotifyDataCallback) {
  wx.onBLECharacteristicValueChange(function(res){
    if (ble_getNotifyDataCallback) {
      ble_getNotifyDataCallback(res.value)
    }
  })
}

function ble_sendDataByUUIDs(service_uuid, char_uuid, sendData) {
  if(data.isConnected) {
    var sendDataBuffer = new ArrayBuffer(sendData.length)
    var unint8_sendDataBuffer = new Uint8Array(sendDataBuffer)
    for (let i = 0; i < sendData.length; i++) {
      unint8_sendDataBuffer[i] = sendData.charCodeAt(i)
    }

    wx.writeBLECharacteristicValue({
      deviceId: data.ble_device.deviceId,
      serviceId: service_uuid,
      characteristicId: char_uuid,
      value: sendDataBuffer,
      success: function (res) {
        if (private_data.showDebugMsgEnable) {
          console.log("Send data success")
        }
      },
      fail: function (res) {
        if (private_data.showDebugMsgEnable) {
          console.log("Send data failed")
        }
      }
    })
  } else {
    if(private_data.showDebugMsgEnable) {
      console.log("ble not connect yet")
    }
  }
  
}

function ble_changeUUIDs(service_uuid, char_uuid, ble_changeUUIDsCallback) {
  if(data.isConnected) {
    console.log("find uuids")
    data.service_uuid = null,
    data.char_uuid = null,

    wx.getBLEDeviceServices({
      deviceId: data.ble_device.deviceId,
      success: function(res) {
        res.services.forEach(function(service, index) {
          if(service.uuid == service_uuid) {
            wx.getBLEDeviceCharacteristics({
              deviceId: data.ble_device.deviceId,
              serviceId: service.uuid,
              success: function(res) {
                res.characteristics.forEach(function(char, index) {
                  if(char.uuid == char_uuid) {
                    // Storage the value
                    data.service_uuid = service.uuid
                    data.char_uuid = char.uuid
                    if (ble_changeUUIDsCallback) {
                      ble_changeUUIDsCallback()
                    }
                  }
                })
              },
            })
          }
        })
      },
    })
  } else {
    if(private_data.showDebugMsgEnable) {
      console.log("ble not connect yet")
    }
  }
}

function ble_sendData(sendData) {
  if(!data.service_uuid || !data.char_uuid) {
    console.log(data.service_uuid + " " + data.char_uuid)
    if(private_data.showDebugMsgEnable) {
      console.log("uuids null")
    }
  } else {
    ble_sendDataByUUIDs(data.service_uuid, data.char_uuid, sendData)
  }
}

function getStringFromBuffer(buffer) {
  var arr = Array.prototype.map.call(new Uint8Array(buffer), x => x)
  var str = ''
  for (var i = 0; i < arr.length; i++) {
    str += String.fromCharCode(arr[i])
  }
  return str
}

function getCharsFromInt (int_data) {
  var int_datas = new ArrayBuffer(4)
  var int32 = new Int32Array(int_datas)
  int32[0] = int_data
  return int_datas
}

function getIntFromString(string) {
  if (string.length != 4) {
    return
  } else {
    var int_array = new ArrayBuffer(4)

    var string_uchars = new Uint8Array(string.split('').map(function (c) {
      return c.charCodeAt(0)
    }))
    var array_uchars = new Uint8Array(int_array)

    array_uchars[0] = string_uchars[0]
    array_uchars[1] = string_uchars[1]
    array_uchars[2] = string_uchars[2]
    array_uchars[3] = string_uchars[3]

    var int_data = new Int32Array(int_array)

    return int_data[0]
  }
}

function getStringFromInt(int_data) {
  var basic_arr = getCharsFromInt(int_data)
  var string = ""
  var i = new DataView(basic_arr)

  for (let s = 0; s < i.byteLength; s++) {
    string += String.fromCharCode(i.getUint8(s));
  }
  return string

}

module.exports = {
  data: data,

  setShowDialogEnable: setShowDialogEnable,
  getShowDialogEnable: getShowDialogEnable,
  setshowDebugMsgEnable: setshowDebugMsgEnable,
  getshowDebugMsgEnable: getshowDebugMsgEnable,
  ble_onAdapterStatesChanged: ble_onAdapterStatesChanged,
  ble_openAdaptorandStartDiscovery: ble_openAdaptorandStartDiscovery,
  ble_onDeviceFound: ble_onDeviceFound,
  ble_getDeviceinFoundDeviceListByName: ble_getDeviceinFoundDeviceListByName,
  ble_connectToDevice: ble_connectToDevice,
  ble_stopDiscovery: ble_stopDiscovery,
  ble_setDevice: ble_setDevice,
  ble_getDevice: ble_getDevice,
  ble_disconnect: ble_disconnect,
  ble_turnOnNotify: ble_turnOnNotify,
  ble_getNotifyData: ble_getNotifyData,
  ble_sendDataByUUIDs: ble_sendDataByUUIDs,
  ble_changeUUIDs: ble_changeUUIDs,
  ble_sendData: ble_sendData,

  getStringFromBuffer: getStringFromBuffer,
  getCharsFromInt: getCharsFromInt,
  getStringFromInt: getStringFromInt,
  getIntFromString: getIntFromString
}